package com.fkcai.hansoul.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fkcai.hansoul.common.constant.PostConstant;
import com.fkcai.hansoul.common.util.ResultCode;
import com.fkcai.hansoul.model.dto.post.PostDraftDto;
import com.fkcai.hansoul.common.constant.UserConstant;
import com.fkcai.hansoul.model.dto.post.PostCreateDto;
import com.fkcai.hansoul.model.vo.post.GetPostVo;
import com.fkcai.hansoul.model.vo.post.PostBaseInfoVo;
import com.fkcai.hansoul.model.entity.Post;
import com.fkcai.hansoul.model.entity.PostCategoryTwo;
import com.fkcai.hansoul.model.entity.PostImage;
import com.fkcai.hansoul.model.entity.User;
import com.fkcai.hansoul.common.exception.ComFoundException;
import com.fkcai.hansoul.mapper.PostCategoryTwoMapper;
import com.fkcai.hansoul.mapper.PostImageMapper;
import com.fkcai.hansoul.mapper.PostMapper;
import com.fkcai.hansoul.mapper.UserMapper;
import com.fkcai.hansoul.service.FileService;
import com.fkcai.hansoul.service.PostService;
import com.fkcai.hansoul.common.util.ThreadLocalUtil;
import com.fkcai.hansoul.common.util.UserUtil;
import com.fkcai.hansoul.model.vo.post.PostFullInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * 实现用户发帖业务逻辑接口的具体实现方法
 */
@Service
@Slf4j
public class PostServiceImpl implements PostService {
	@Autowired
	private PostMapper postMapper;
	@Autowired
	private UserMapper userMapper;
	@Autowired
	private PostImageMapper postImageMapper;
	@Autowired
	private PostCategoryTwoMapper postCategoryTwoMapper;
	@Autowired
	private FileService fileService;
	@Autowired
	private TransactionTemplate transactionTemplate;
	
	// 添加随机种子生成器
	private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
	
	
	/**
	 * 创建帖子实现类
	 *
	 * @param request 帖子信息
	 * @param images  图片列表
	 * @return 帖子响应数据
	 */
	@Override
	@Transactional(
			propagation = Propagation.REQUIRED, // 如果当前存在事务，就加入该事务；否则创建新事务。
			rollbackFor = Exception.class,
			timeout = 60 // 创建帖子可能需要更长时间
	)
	public PostBaseInfoVo createPost (PostCreateDto request, List<MultipartFile> images) {
		int authorId = getAuthorId();
		
		// 校验分类是否存在
		Integer categoryId = request.getCategoryId();
		PostCategoryTwo category = postCategoryTwoMapper.selectById(categoryId);
		if (category == null) {
			throw new ComFoundException(ResultCode.CATEGORY_NOT_FOUND);
		}
		
		// 检验帖子
		checkCreatePost(request);
		
		// 上传图片到服务器
		List<String> imageUrls = uploadImages(images);
		
		// 转换 DTO 到实体类
		Post post = new Post();
		BeanUtils.copyProperties(request, post);
		post.setAuthorId(authorId);
		post.setContent(UserUtil.replaceSensitiveWords(request.getContent()));
		post.setTitle(UserUtil.replaceSensitiveWords(request.getTitle()));
		post.setCreateTime(LocalDateTime.now());
		post.setPostStatus("public");
		post.setReviewStatus("approved");
		
		postMapper.insert(post);
		
		// 保存图片到图片表
		if (!imageUrls.isEmpty()) {
			for (String imgUrl : imageUrls) {
				PostImage postImage = new PostImage();
				postImage.setPostId(post.getPostId());
				postImage.setFileUrl(imgUrl);
				
				postImageMapper.insert(postImage);
			}
		}
		
		// 返回响应数据
		PostBaseInfoVo response = new PostBaseInfoVo();
		response.setUserId(authorId);
		response.setPostId(post.getPostId());
		response.setContent(post.getContent());
		response.setTitle(post.getTitle());
		response.setCategoryId(post.getCategoryId());
		response.setCreateTime(post.getCreateTime());
		response.setPostStatus(post.getPostStatus());
		// response.setVideoUrl(videoUrl);
		response.setImageUrls(imageUrls);
		
		return response;
	}
	
	
	/**
	 * 创建草稿实现类
	 *
	 * @param request 草稿信息
	 * @param images  图片列表
	 * @return 创建的草稿信息
	 */
	@Override
	@Transactional(
			propagation = Propagation.REQUIRED,
			rollbackFor = Exception.class
	)
	public PostBaseInfoVo createPostDraft (PostDraftDto request, List<MultipartFile> images) {
		int authorId = getAuthorId();
		
		if (StringUtils.isBlank(request.getTitle())) {
			throw new ComFoundException(ResultCode.POST_TITLE_NOT_NULL);
		}
		if (StringUtils.length(request.getTitle()) > PostConstant.POST_TITLE_LENGTH_MAX) {
			throw new ComFoundException(ResultCode.POST_TITLE_TOO_LONG);
		}
		
		List<String> imageUrls = uploadImages(images);
		
		// 转换 DTO 到实体类
		Post post = new Post();
		BeanUtils.copyProperties(request, post);
		
		if (post.getCategoryId() == null) {
			post.setCategoryId(6); // 使用 6 表示未分类
		}
		
		post.setAuthorId(authorId);
		post.setContent(UserUtil.replaceSensitiveWords(request.getContent()));
		post.setTitle(UserUtil.replaceSensitiveWords(request.getTitle()));
		post.setCreateTime(LocalDateTime.now());
		post.setPostStatus("draft");
		post.setReviewStatus("approved");
		
		postMapper.insert(post);
		
		// 保存图片到图片表
		if (!imageUrls.isEmpty()) {
			for (String imgUrl : imageUrls) {
				PostImage postImage = new PostImage();
				postImage.setPostId(post.getPostId());
				postImage.setFileUrl(imgUrl);
				
				postImageMapper.insert(postImage);
			}
		}
		
		// 返回响应数据
		PostBaseInfoVo response = new PostBaseInfoVo();
		response.setUserId(authorId);
		response.setPostId(post.getPostId());
		response.setContent(post.getContent());
		response.setTitle(post.getTitle());
		response.setCategoryId(post.getCategoryId());
		response.setCreateTime(post.getCreateTime());
		response.setPostStatus(post.getPostStatus());
		// response.setVideoUrl(videoUrl);
		response.setImageUrls(imageUrls);
		
		return response;
	}
	
	
	/**
	 * 获取用户帖子
	 *
	 * @param userId 用户 id
	 * @return 用户帖子
	 */
	@Override
	@Transactional(readOnly = true)
	public List<GetPostVo> getPostsByUserId (Integer userId) {
		int authorId = getAuthorId();
		
		List<GetPostVo> posts = postMapper.getPostsByUserId(authorId);
		
		return posts.stream().map(post -> {
			GetPostVo getPostVo = new GetPostVo();
			BeanUtils.copyProperties(post, getPostVo);
			
			GetPostVo.UserInfo userInfo = new GetPostVo.UserInfo();
			userInfo.setUserId(post.getUser().getUserId());
			userInfo.setAvatarUrl(post.getUser().getAvatarUrl());
			userInfo.setUsername(post.getUser().getUsername());
			post.setUser(userInfo);
			
			List<PostImage> images = postImageMapper.selectList(
					new QueryWrapper<PostImage>()
							.eq("post_id", post.getPostId())
			);
			
			getPostVo.setImageUrls(images.stream()
					.map(PostImage::getFileUrl)
					.collect(Collectors.toList())
			);
			
			return getPostVo;
		}).collect(Collectors.toList());
	}
	
	
	/**
	 * 获取帖子详情
	 *
	 * @param postId 帖子 id
	 * @return 帖子详细信息
	 */
	@Override
	@Transactional(readOnly = true)
	public PostFullInfoVo getPostByPostId (Integer postId) {
		PostFullInfoVo post = postMapper.getPostByPostId(postId);
		
		if (post == null) {
			throw new ComFoundException(ResultCode.POST_NOT_EXIST);
		}
		
		return post;
	}
	
	
	/**
	 * 根据分类 id 获取帖子
	 * @param categoryId 分类 id
	 * @param page 页码
	 * @param size 每页数量
	 * @return 帖子列表
	 */
	@Override
	public List<GetPostVo> getPostsByCategoryId (Integer categoryId, int page, int size) {
		// 检验分类是否存在
		PostCategoryTwo category = postCategoryTwoMapper.selectById(categoryId);
		
		if (category == null) {
			throw new ComFoundException(ResultCode.CATEGORY_NOT_FOUND);
		}
		
		int offset = page * size;
		
		// 获取随机种子
		int randomSeed = RANDOM.nextInt(1000);
		
		return postMapper.selectPublicPostsByCategoryId(categoryId, offset, size,randomSeed);
	}
	
	
	/**
	 * 获取所有帖子
	 * @return 所有帖子
	 */
	@Override
	public List<GetPostVo> getAllPosts (int page, int size) {
		int offset = page * size;
		
		// 获取随机种子
		int randomSeed = RANDOM.nextInt(1000);
		
		return postMapper.selectAllPublicPosts(offset, size, randomSeed);
	}
	
	/**
	 * 获取分类下的帖子数量
	 * @param categoryId 分类 id
	 * @return 帖子数量
	 */
	@Override
	public Long countPosts (Integer categoryId) {
		// 如果分类 id 为 null，则返回所有帖子数量
		if (categoryId == null) {
			return postMapper.countAllPublicPosts();
		} else {
			return postMapper.countPublicPostsByCategoryId(categoryId);
		}
	}
	
	
	
	/* ================================ 公用方法 ================================================= */
	
	
	/**
	 * 获取当前用户 id, 即帖子创建者 id
	 *
	 * @return 当前用户 id
	 */
	private int getAuthorId () {
		// 获取当前用户 id
		String userId = ThreadLocalUtil.get();
		if (userId == null) throw new ComFoundException(ResultCode.USER_NOT_LOGIN);
		
		// 将当前用户 id 的类型转换为 int 类型
		int authorId = Integer.parseInt(userId);
		
		// 检验用户状态
		User user = userMapper.selectById(authorId);
		if (user == null) throw new ComFoundException(ResultCode.USER_NOT_EXIST);
		if (user.getAccountStatus() == UserConstant.DISABLED)
			throw new ComFoundException(ResultCode.USER_ACCOUNT_ANOMALY);
		
		return authorId;
	}
	
	
	/**
	 * 检验帖子
	 *
	 * @param request 帖子信息
	 */
	private void checkCreatePost (PostCreateDto request) {
		// 检查标题是否为空
		if (StringUtils.isBlank(request.getTitle())) {
			throw new ComFoundException(ResultCode.POST_TITLE_NOT_NULL);
		}
		
		// 检查内容是否为空
		if (StringUtils.isBlank(request.getContent())) {
			throw new ComFoundException(ResultCode.POST_CONTENT_NOT_NULL);
		}
		
		// 检查分类是否为空
		if (request.getCategoryId() == null) {
			throw new ComFoundException(ResultCode.CATEGORY_NOT_NULL);
		}
		
		// 检查标题长度
		if (StringUtils.length(request.getTitle()) > PostConstant.POST_TITLE_LENGTH_MAX) {
			throw new ComFoundException(ResultCode.POST_TITLE_TOO_LONG);
		}
		
		// 检查内容长度
		if (StringUtils.length(request.getContent()) > PostConstant.POST_CONTENT_LENGTH_MAX) {
			throw new ComFoundException(ResultCode.POST_CONTENT_TOO_LONG);
		}
	}
	
	
	/**
	 * 上传图片
	 *
	 * @param images 图片列表
	 * @return 图片 url 列表
	 */
	private List<String> uploadImages (List<MultipartFile> images) {
		List<String> imageUrls = new ArrayList<>();
		
		try {
			for (MultipartFile img : images) {
				String imgUrl = fileService.uploadFile(img, "image");
				imageUrls.add(imgUrl);
			}
			
			return imageUrls;
		} catch (Exception e) {
			// 部分上传成功时回滚已传文件
			imageUrls.forEach(url -> {
				try {
					fileService.deleteFile(url);
				} catch (Exception ex) {
					log.error("文件删除失败: {}", url, ex);
				}
			});
			
			throw new ComFoundException(ResultCode.FILE_UPLOAD_ERROR);
		}
	}
	
}
